package com.emergency.embackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.emergency.embackend.dto.UserDTO;
import com.emergency.embackend.entity.User;
import com.emergency.embackend.exception.EmException;
import com.emergency.embackend.mapper.UserMapper;
import com.emergency.embackend.param.UserParam;
import com.emergency.embackend.param.UserPasswordParam;
import com.emergency.embackend.service.UserService;
import com.emergency.embackend.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author chddd
 * @description
 * @create 2024/1/27 13:43:35
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Override
    public String saveCode(String phone) {
        //生成验证码
        String code = RandomUtil.randomNumbers(6);
        //存储到redis并设置5分钟的过期时间
        stringRedisTemplate.opsForValue().set(RedisConstants.LOGIN_USER_CODE+phone,code);
        stringRedisTemplate.expire(RedisConstants.LOGIN_USER_CODE+phone, RedisConstants.LOGIN_CODE_TTL, TimeUnit.SECONDS);
        return code;
    }

    @Override
    public String login(UserParam userParam) {
        User user;
        if(TypeUtils.LOGIN_ACCOUNT.equals(userParam.getLoginType())){
            //根据 用户账号登陆
            user = loginByAccount(userParam);
        }else if(TypeUtils.LOGIN_PHONE.equals(userParam.getLoginType())){
            user = loginByPhone(userParam);
        }else{
            throw new EmException("401","参数不正确，请联系管理员");
        }
        String res;
        //保存用户到redis中,这里要以随机的token为key
        // 使用hash数据类型来存储用户数据
        //随机生成token，作为登陆令牌
        String token = JWTUtils.getJwtToken(user.getId(),user.getUsername());
        //将User对象转换为Hash存储
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        //解决long类型和String类型之间的转换，因为id是long类型
        Map<String, Object> map = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> ObjectUtil.isNull(fieldValue) ? null : fieldValue.toString()));
        stringRedisTemplate.opsForHash().putAll(RedisConstants.LOGIN_USER_KEY+token,map);
        stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY+token,RedisConstants.LOGIN_TOKEN_TTL,TimeUnit.DAYS);
        res = token;
        return res;
    }

    private User loginByPhone(UserParam userParam) {
        //检验验证码
        checkCode(userParam.getPhone(),userParam.getCode());
        //一样，根据手机号查询用户
        User user =userMapper.searchUser(userParam);
        if(user==null){
            //不存在，则创建新用户并保存
            user=createUserWithPhone(userParam.getPhone());
        }
        return user;
    }

    /**
     * 用于检验验证码
     * @param phone
     * @param inCode
     * @return
     */
    private boolean checkCode(String phone,String inCode){
        //从redis中获取验证码并且校验验证码
        String code = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_USER_CODE + phone);
        //不一样，报错
        if(code==null){
            throw new EmException("401", "验证码已失效，请重新获取");
        }
        if(!code.equals(inCode)){
            throw new EmException("401", "验证码输入错误");
        }
        return true;
    }

    private User loginByAccount(UserParam userParam) {
        //检测账号和密码是否存在
        User user = userMapper.searchUser(userParam);
        if(user == null){
            throw new EmException("500","请核对账号密码");
        }
        if(user.getPassword() == null) {
            throw new EmException("401","请用手机登录，该账号未初始化密码");
        }
        return user;
    }

    @Override
    public Boolean register(UserParam userParam) {
        if(StrUtil.isEmpty(userParam.getUsername())){
            //号码为空不允许注册
            throw new EmException("500","用户名不可以为空");
        }
        //通过电话号码判断是否已经存在
        User user = userMapper.searchUser(userParam);
        if(user != null) {
            return false;
        }
        User registerUser = new User();
        BeanUtils.copyProperties(userParam,registerUser);
        registerUser.setCreateTime(new Date());
        if(registerUser.getIcon() == null){
            registerUser.setIcon("https://test-1316698763.cos.ap-guangzhou.myqcloud.com/user-avatar/def-avatar.png");
        }
        Date date = new Date();
        registerUser.setCreateTime(date);
        registerUser.setUpdateTime(date);
        userMapper.register(registerUser);
        return true;
    }

    @Override
    public User info(Long id) {
       return userMapper.info(id);
    }

    @Override
    public void update(UserParam userParam, HttpServletRequest request) {
        userParam.setUpdateTime(new Date());
        userMapper.update(userParam);
        UserHolder.removeUser();
        User newUser = userMapper.info(userParam.getId());
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(newUser,userDTO);
        //刷新redis用户数据
        //解决long类型和String类型之间的转换，因为id是long类型
        reNewRedisUser(request,userDTO);
        UserHolder.saveUser(userDTO);
    }

    @Override
    public Boolean updatePassword(UserPasswordParam userPasswordParam) {
        if(!userPasswordParam.getNewPassword().equals(userPasswordParam.getConfirmPassword())){
            throw new EmException("401","两次新密码输入不相同");
        }
        if(userPasswordParam.getOldPassword().equals(userPasswordParam.getConfirmPassword())){
            throw new EmException("401","新旧密码相同请重新输入");
        }
        User user = userMapper.info(userPasswordParam.getId());
        if(!user.getPassword().equals(userPasswordParam.getOldPassword())){
            throw new EmException("401","旧密码输入错误,请重新输入");
        }
        UserParam userParam = new UserParam();
        userParam.setId(userPasswordParam.getId());
        userParam.setPassword(userPasswordParam.getNewPassword());
        userParam.setUpdateTime(new Date());
        userMapper.update(userParam);
        UserHolder.removeUser();
        return true;
    }

    @Override
    @Async
    public void sendCode(String phone,String code) {
        String host = "https://gyytz.market.alicloudapi.com";
        String path = "/sms/smsSend";
        String method = "POST";
        String appcode = "dee23f6d818b4830b8f15eb52b66af8e";
        Map<String, String> headers = new HashMap<>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<>();
        querys.put("mobile", phone);
        querys.put("param", "**code**:"+code+"**minute**:5");

//smsSignId（短信前缀）和templateId（短信模板），可登录国阳云控制台自助申请。参考文档：http://help.guoyangyun.com/Problem/Qm.html

        querys.put("smsSignId", "2e65b1bb3d054466b82f0c9d125465e2");
        querys.put("templateId", "908e94ccf08b4476ba6c876d13f084ad");
        Map<String, String> bodys = new HashMap<String, String>();


        try {
            /**
             * 重要提示如下:
             * HttpUtils请从\r\n\t    \t* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java\r\n\t    \t* 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             */
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println(response.toString());
            //获取response的body
            //System.out.println(EntityUtils.toString(response.getEntity()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Boolean bindingPhone(String phone, Long userId,String code,HttpServletRequest request) {
       checkCode(phone,code);
       checkPhoneIsExist(phone);
        UserParam userParam = new UserParam();
        userParam.setId(userId);
        userParam.setPhone(phone);
        userMapper.update(userParam);
        User info = userMapper.info(userId);
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(info,userDTO);
        UserHolder.saveUser(userDTO);
        reNewRedisUser(request,userDTO);
        log.info("用户数据:{}",UserHolder.getUser());
        return true;
    }

    private void checkPhoneIsExist(String phone) {
        UserParam userParam = new UserParam();
        userParam.setPhone(phone);
        User user = userMapper.searchUser(userParam);
       if(user != null){
           throw new EmException("401","用户号码已绑定，请直接登陆");
       }
    }


    private User createUserWithPhone(String phone) {
        User user = new User();
        user.setPhone(phone);
        String name = "user_" + RandomUtil.randomString(10);
        user.setUsername(phone);
        user.setNickName(name);
        user.setIcon("https://test-1316698763.cos.ap-guangzhou.myqcloud.com/user-avatar/def-avatar.png");
        user.setPassword("123456");
        userMapper.register(user);
        return user;
    }

    public void reNewRedisUser(HttpServletRequest request,UserDTO userDTO){
        String token = request.getHeader("token");
        String key = RedisConstants.LOGIN_USER_KEY + token;
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
        //判断用户是否存在
        if (userMap.isEmpty()||!JWTUtils.checkToken(token)) {
            throw new EmException("401","token失效");
        }
        Map<String,Object> map= BeanUtil.beanToMap(userDTO,new HashMap<>(),
                CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue)->fieldValue.toString()));
        //更新redis的数据
        stringRedisTemplate.opsForHash().putAll(key,map);
        stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY+token,RedisConstants.LOGIN_TOKEN_TTL,TimeUnit.DAYS);
    }
}
